﻿
using System;
using System.Linq;
using System.Reflection;

namespace QQ2564874169.Core.Utils
{
    public static class ConvertHelper
    {
        private const string keys = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        private static int exponent = keys.Length;
        private static DateTime _startTime = new DateTime(1970, 1, 1).ToUniversalTime();

        /// <summary>
        /// 数字转64进制
        /// </summary>
        public static string NumTo64(decimal value)
        {
            var result = string.Empty;
            do
            {
                var index = value % exponent;
                result = keys[(int)index] + result;
                value = (value - index) / exponent;
            }
            while (value > 0);

            return result;
        }

        /// <summary>
        /// 64进制字符串转数字
        /// </summary>
        public static decimal ToNumBy64(string value)
        {
            decimal result = 0;
            for (var i = 0; i < value.Length; i++)
            {
                var x = value.Length - i - 1;
                result += keys.IndexOf(value[i]) * Pow(exponent, x);
            }
            return result;
        }

        private static decimal Pow(decimal baseNo, decimal x)
        {
            decimal value = 1;
            while (x > 0)
            {
                value = value * baseNo;
                x--;
            }
            return value;
        }

        public static long ToLongTime(DateTime time, DateAccuracy accuracy = DateAccuracy.Second)
        {
            var date = time.ToUniversalTime() - _startTime;
            switch (accuracy)
            {
                case DateAccuracy.Day:
                    return (long)date.TotalDays;
                case DateAccuracy.Hour:
                    return (long)date.TotalHours;
                case DateAccuracy.Minute:
                    return (long)date.TotalMinutes;
                case DateAccuracy.Second:
                    return (long)date.TotalSeconds;
                case DateAccuracy.Millisecond:
                    return (long)date.TotalMilliseconds;
                default:
                    throw new NotSupportedException(accuracy.ToString());
            }
        }

        public static DateTime ToDate(long time, DateAccuracy accuracy = DateAccuracy.Second)
        {
            switch (accuracy)
            {
                case DateAccuracy.Day:
                    return _startTime.AddDays(time);
                case DateAccuracy.Hour:
                    return _startTime.AddHours(time);
                case DateAccuracy.Minute:
                    return _startTime.AddMinutes(time);
                case DateAccuracy.Second:
                    return _startTime.AddSeconds(time);
                case DateAccuracy.Millisecond:
                    return _startTime.AddMilliseconds(time);
                default:
                    throw new NotSupportedException(accuracy.ToString());
            }
        }

        public static T Map<T>(object source)
        {
            var tps = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public).ToArray();
            var sps = source.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
            var obj = Activator.CreateInstance<T>();
            foreach (var p in tps.ToArray())
            {
                if (p.CanWrite == false)
                    continue;
                var sp = sps.FirstOrDefault(i => i.Name == p.Name);
                if (sp == null)
                    continue;
                var value = sp.GetValue(source, null);
                if (value != null)
                {
                    if (p.PropertyType.IsEnum && sp.PropertyType.IsPrimitive)
                    {
                        value = Enum.Parse(p.PropertyType, value.ToString());
                    }
                    else
                    {
                        value = Convert.ChangeType(value, p.PropertyType);
                    }
                    p.SetValue(obj, value, null);
                }
            }
            return obj;
        }
    }
}
